package org.noote.libs.computervision.math;

public class Segment2D {
	
	public Point2D start=new Point2D(0, 0);
	public Point2D end=new Point2D(0, 0);
	public Vector2D slope = new Vector2D(0, 0);

	public Segment2D()
	{
	}
	
	public Segment2D(Point2D start, Point2D end, Vector2D slope)
	{
		this.start = start;
		this.end = end;
		this.slope = slope;
	}
	public void set(Point2D start, Point2D end)
	{
		this.start = start;
		this.end = end;
		rebuild();
	}
	
	public float getLength()
	{
		// longueur du segment
		float d1 = (start.x-end.x);
		float d2 = (start.y-end.y);

		return (float)Math.sqrt((d1*d1)+(d2*d2));
	}
	public float getDistance(Point2D p)
	{
		// longueur du segment
		float d1 = (start.x-end.x);
		float d2 = (start.y-end.y);

		// distance du point par rapport au segment
		float cross = (float)(end.x-start.x) * (float)(p.y-start.y);
		cross -= (float)(end.y-start.y) *(float)(p.x-start.x);

		float distance = cross;
		distance /= (float)Math.sqrt((d1*d1)+(d2*d2));
		
		return Math.abs(distance);
	}
	public void rebuild()
	{
		slope = new Vector2D(end.x - start.x, end.y - start.y);
		slope.normalize();

		if(Math.abs(slope.x)>Math.abs(slope.y))
		{
			if(end.x<start.x)
			{
				Point2D w=start;
				start = end;
				end = w;
			}
		}
		else
		{
			if(end.y<start.y)
			{
				Point2D w=start;
				start = end;
				end = w;
			}				
		}
	}
	public boolean isMergeable(Segment2D s, float fColinearDistanceMax, float fDistanceMax)
	{
		// pente compatible ?
		if(Math.abs(s.slope.x-slope.x)>0.05f || Math.abs(s.slope.y-slope.y)>0.05f)
			return false;
		
		// sur la meme ligne virtuelle ?
		if(getDistance(s.start)>fColinearDistanceMax || getDistance(s.end)>fColinearDistanceMax)
			return false;

/*
		// TODO : verifie si les limites sont compatible ?
		Vector2D vSS = new Vector2D(s.start.x - start.x, s.start.y - start.y);
		Vector2D vSE = new Vector2D(s.start.x - end.x, s.start.y - end.y);
		Vector2D vEE = new Vector2D(s.end.x - end.x, s.end.y - end.y);
		Vector2D vES = new Vector2D(s.end.x - start.x, s.end.y - start.y);
		float fSS = vSS.getLength();
		float fSE = vSE.getLength();
		float fEE = vEE.getLength();
		float fES = vES.getLength();

		float fL = getLength();
		float fSL = s.getLength();
		if(fSS>fL && fEE>fSL)
		{
			if((fSS-fSE)>fDistanceMax)
				return false;
		}
*/		
		return true;
	}
	public void merge(Point2D p)
	{
		merge(p, true);
	}
	public void merge(Point2D p, boolean bRebuild)
	{
		if(Math.abs(slope.x)>Math.abs(slope.y))
		{
			if(p.x<start.x)
				start = p;
			else if(p.x>end.x)
				end = p;
		}
		else
		{
			if(p.y<start.y)
				start = p;
			else if(p.y>end.y)
				end = p;				
		}
		if(bRebuild)
			rebuild();
	}
	public void merge(Segment2D s)
	{
		// TODO : find a better segment to segment merger algo
		merge(s.start, false);
		merge(s.end, false);
		rebuild();
	}
	public Point2D findIntersection(Segment2D s)
	{
		float denom = ((s.end.y - s.start.y)*(end.x - start.x)) -
			((s.end.x - s.start.x)*(end.y - start.y));

		float nume_a = ((s.end.x - s.start.x)*(start.y - s.start.y)) -
			((s.end.y - s.start.y)*(start.x - s.start.x));

		if(denom<1e-6 || nume_a<1e-6)
			return null;
		
		float ua = nume_a / denom;

		float x = start.x + ua * (end.x - start.x);
		float y = start.y + ua * (end.y - start.y);

		return new Point2D((int)x, (int)y);
	}
	public float calcul_orientation()
	{
		return (float) Math.atan2(start.x-end.x, end.y-start.y);
	}
}
